#include "control.h"

#include "waterTank.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <QString>
#include <QHeaderView>

//Control::Control(QTableWidget view)
Control::Control()
{
    //this->view = &view;
    //this->view  = new QTableWidget(0, 6);
    sem_init(&semaphorePump, 0, 1);//inicia o semáforo Wt1
    sem_init(&semaphoreWt1, 0, 1);//inicia o semáforo Wt1
    sem_init(&semaphoreWt2, 0, 1);//inicia o semáforo Wt2
    pumpOutput = 5.0/(1000*60.0);
    pumpStatus = false;
    tap1Closed = false;
    tap2Closed = false;
    totalTimeWt1Clear = 50; //500
    totalTimeWt2Clear = 30; //300
    wt1Full = false;
    wt2Full = false;
    wt1 = new WaterTank();
    wt2 = new WaterTank();
    //sleep_for (std::chrono::seconds(1))
}

Control::~Control()
{
    //sem_destroy(&semaphorePump);//destroi o semáforo
    //sem_destroy(&semaphoreWt1);//destroi o semáforo
    //sem_destroy(&semaphoreWt2);//destroi o semáforo
    delete wt1;
    delete wt2;
}

void Control::control_print_data(){

    QString pump, semPump, semWt1, semWt2, level1, level2;
    int valSemPump = 0;
    int valSemWt1 = 0;
    int valSemWt2 = 0;

    sem_getvalue(&semaphorePump, &valSemPump);
    sem_getvalue(&semaphoreWt1, &valSemWt1);
    sem_getvalue(&semaphoreWt2, &valSemWt2);
    level1.number(wt1->WaterTank_GetLevel(),'f',4);
    level2.number(wt2->WaterTank_GetLevel(),'f',4);

    if(pumpStatus) pump = "ligada";
    else    pump = "desligada";

    if(valSemPump)  semPump = "fechado";
    else  semPump = "aberto";

    if(valSemWt1)  semWt1 = "fechado";
    else  semWt1 = "aberto";

    if(valSemWt2)  semWt2 = "fechado";
    else  semWt2 = "aberto";

    emit control_signal_print(pump, semPump, semWt1, semWt2, level1, level2);

    //printf("%s \t %s \t %s \t s \t %s \t %s \n",pump, semPump, semWt1, semWt2,
    //       level1, level2);
}


void Control::run()
{
     //qDebug() << "hello from worker thread " << thread()->currentThreadId();
    //Cria os theads filhos do processo
    try{

        printf("Pump \t SemPump \t SemWt1 \t SemWt2 \t LevelWt1 \t LevelWt2 \n");

        //Control_Print();

        //Mudança 13_05
        if(wt1->WaterTank_GetLevel()>=wt1->WaterTank_GetHeight())   wt1Full = true;

        if(wt2->WaterTank_GetLevel()>=wt2->WaterTank_GetHeight())   wt2Full = true;

        pthread_create(&pump_control, NULL, Control_Pump_Control_Helper,this);

        if(tap1Open){
            pthread_create(&wt1_clean, NULL, Control_Wt1_Clear_Helper,this);
        }
        if(tap2Open){
            pthread_create(&wt2_clean, NULL, Control_Wt2_Clear_Helper,this);
        }

        if((clock()/(CLOCKS_PER_SEC))%6==0) control_print_data();

        pthread_join(wt1_clean, NULL);
        pthread_join(wt2_clean, NULL);
        pthread_join(pump_control, NULL);

    }
    catch(char *error){
        printf("Exception: %s \n", error);
        //return NOT;
    }
    //return OK;


}

/*int Control::Control_Main(void)
{
}*/

int Control::Control_Stop(void)
{
    pthread_exit(&wt1_fill);
    pthread_exit(&wt2_fill);
    pthread_exit(&wt1_clean);
    pthread_exit(&wt2_clean);
    return OK;
}

void *Control::Control_Pump_Control_Helper(void *pControl)
{
    return ((Control* )pControl)->Control_Pump_Control();
}

void *Control::Control_Pump_Control(){
    bool wt2FillOn = false;
    //bool wt1FillOn = false;
    //tap1Closed
    while(true){
        if(wt1->WaterTank_GetLevel()<=wt1->WaterTank_GetStandartLevel()){
            if(pumpStatus == true){
                if(wt2FillOn){
                    sem_wait(&semaphorePump);
                    pthread_exit(&wt2_fill);
                    wt2FillOn = false;
                    pthread_create(&wt1_fill, NULL, Control_Wt1_Fill_Helper,this);
                }
            }
            else{
                sem_wait(&semaphorePump);
                pumpStatus = true;
                pthread_create(&wt1_fill, NULL, Control_Wt1_Fill_Helper,this);
            }
            //wt1FillOn = true;
            pthread_join(wt1_fill, NULL);
         }
         else{
            if(wt2->WaterTank_GetLevel()<=wt2->WaterTank_GetStandartLevel()){
                if(pumpStatus == false){
                    sem_wait(&semaphorePump);
                    pumpStatus = true;
                    wt2FillOn = true;
                    pthread_create(&wt2_fill, NULL, Control_Wt2_Fill_Helper,this);
                    //pthread_join(wt2_fill, NULL);
                }
            }
        }
    }
    return OK;
}

void *Control::Control_Wt1_Fill_Helper(void *pControl)
{
    return ((Control* )pControl)->Control_Wt1_Fill();
}

void *Control::Control_Wt1_Fill(void)
{
    //int counter = 0;
    time_t currentTime;
    double level = 0.0;
    try
    {
        lastTimeWt1Fill = clock()/(CLOCKS_PER_SEC);
        while(!wt1Full){
            sem_wait(&semaphoreWt1);//espera liberar o semáforo da wt1 e enche wt1
            currentTime = clock()/(CLOCKS_PER_SEC) - lastTimeWt1Fill;
            level = wt1->WaterTank_GetLevel()+wt1->WaterTank_Fill(pumpOutput,currentTime);
            if(level <= (wt1->WaterTank_GetHeight() - 5.0)) wt1->WaterTank_SetLevel(level);
            lastTimeWt1Fill = currentTime;
            //Control_Print();
            if(level> (wt1->WaterTank_GetHeight() - 5.0)){
                wt1Full = true;
                pumpStatus = false;//libera o uso da bomba
                sem_post(&semaphorePump);//libera o semáforo da bomba
            }
            sem_post(&semaphoreWt1);//libera o semáforo da wt1
            //counter++;
            //if(counter%6==0){
        }
    }
    catch(char *error)
    {
        printf("Exception: %s \n", error);
    }
    return OK;
}

void *Control::Control_Wt2_Fill_Helper(void *pControl)
{
    return ((Control* )pControl)->Control_Wt2_Fill();
}

void* Control::Control_Wt2_Fill(void)
{
    double level;
    time_t currentTime;
    try
    {
        lastTimeWt2Fill = clock()/(CLOCKS_PER_SEC);
        while(!wt2Full){
            sem_wait(&semaphoreWt2);//espera liberar o semáforo da wt1 e enche wt1
            currentTime = clock()/(CLOCKS_PER_SEC) - lastTimeWt2Fill;
            level = wt2->WaterTank_GetLevel()+wt2->WaterTank_Fill(pumpOutput,currentTime);
            if(level <= (wt2->WaterTank_GetHeight() - 5.0))  wt2->WaterTank_SetLevel(level);
            lastTimeWt2Fill = currentTime;
            //Control_Print();
            if(level> (wt2->WaterTank_GetHeight() - 5.0)){
                pumpStatus = false;//libera o uso da bomba
                wt2Full = true;
                sem_post(&semaphorePump);//libera o semáforo da bomba
            }
            sem_post(&semaphoreWt2);//libera o semáforo da wt1
        }
    }
    catch(char *error)
    {
        printf("Exception: %s\n", error);
    }
    return OK;
}

void *Control::Control_Wt1_Clear_Helper(void *pControl)
{
    return ((Control* )pControl)->Control_Wt1_Clear();
}

void *Control::Control_Wt1_Clear(void) //dúvida: calcular a vazão ou usar a vazão da torneira?!
{
    double level = wt1->WaterTank_GetLevel();
    time_t currentTime;
    time_t totalTime = 0;
    lastTimeWt1Clear = 0;
    double C = 0.6; //aproximação->mudar para o cálculo
    try
    {
        lastTimeWt1Clear = clock()/(CLOCKS_PER_SEC);
        while((level>0)&&(totalTime<totalTimeWt1Clear)){
            sem_wait(&semaphoreWt1);//espera liberar o semáforo da wt1 e esvazia wt1
            currentTime = clock()/(CLOCKS_PER_SEC) - lastTimeWt1Clear;
            level = wt1->WaterTank_Clear(C, currentTime);
            if(level>0) wt1->WaterTank_SetLevel(level);
            lastTimeWt1Clear = clock()/(CLOCKS_PER_SEC);
            totalTime +=currentTime;
            //if((clock()/(CLOCKS_PER_SEC))%6==0)   Control_Print();
            sem_post(&semaphoreWt1);//libera o semáforo da wt1
        }
        //tap1Closed = true;
    }
    catch(char *error)
    {
        printf("Exception: %s\n", error);
    }
    return OK;
}

void *Control::Control_Wt2_Clear_Helper(void *pControl)
{
    return ((Control* )pControl)->Control_Wt2_Clear();
}

void *Control::Control_Wt2_Clear(void)
{
    double level = wt2->WaterTank_GetLevel();
    time_t currentTime;
    time_t totalTime = 0;
    lastTimeWt2Clear = 0;
    double C = 0.6; //aproximação->mudar para o cálculo
    try
    {
        lastTimeWt2Clear = clock()/(CLOCKS_PER_SEC);
        while((level>0)&&(totalTime<totalTimeWt2Clear)){
            sem_wait(&semaphoreWt2);//espera liberar o semáforo da wt2 e esvazia wt2
            currentTime = clock()/(CLOCKS_PER_SEC) - lastTimeWt2Clear;
            level = wt2->WaterTank_Clear(C, currentTime);
            if(level>0) wt2->WaterTank_SetLevel(level);
            lastTimeWt2Clear = clock()/(CLOCKS_PER_SEC);
            totalTime +=currentTime;
            //Control_Print();
            sem_post(&semaphoreWt2);//libera o semáforo da wt2
        }
        //tap2Closed = true;
    }
    catch(char *error)
    {
        printf("Exception: %s\n", error);
    }
    return OK;
}


void Control::Control_SetSisternCapacity(double sisternCapacity)
{
    this->sisternCapacity = sisternCapacity;
}

void Control::Control_SetPumpOutput(double pumpOutput)
{
    this->pumpOutput = pumpOutput;
}

void Control::Control_SetTimeTap1(double totalTimeWt1Clear){
    this->totalTimeWt1Clear = totalTimeWt1Clear;
}

void Control::Control_SetTimeTap2(double totalTimeWt2Clear){
    this->totalTimeWt2Clear = totalTimeWt2Clear;
}

WaterTank *Control::Control_GetWaterTank(int option)
{
    if(option == 2) return wt2;
    return wt1;
}
